#include "generate.h"
#include "calculate.h"
#include "gen_oper.h"
#include "gen_perm.h"
#include "gen_tree.h"
#include "is_valid.h"

#define TARGET 24
#define MAX_SOLUTION_NUMS 100

typedef struct {
	u64_s* value_n_p;
	u64_s value_a[MAX_SOLUTION_NUMS];
} value_space_t;

// 判断算式有效且不与已有的重复，并执行deal操作。
static void _deal_if_valid_single(const tree34_t* tree_p, deal_tree_ft* deal_f,
				  value_space_t* space_p) {
	u64_s value = cal_tree_value(tree_p);
	if (!value) {
		return;
	}

	fraction_t result = calculate_tree(tree_p);
	if (result.numerator != TARGET || result.denominator != 1) {
		return;
	}

	u64_s* value_n_p = space_p->value_n_p;
	u64_s* value_b = space_p->value_a;
	for (const u64_s* p = value_b; p < value_n_p; p++) {
		if (value == *p) {
			return;
		}
	}
	*value_n_p = value;
	space_p->value_n_p = value_n_p + 1;

	deal_f(tree_p);
}

static void _generate_perm_deal(num_group_s num_group, deal_tree_ft* deal_f,
				value_space_t* space_p, tree34_t* tree_p,
				gen_perm_data_t* gen_perm_data_p) {
	while (1) {
		_deal_if_valid_single(tree_p, deal_f, space_p);
		if (!gen_perm_has_next(gen_perm_data_p)) {
			break;
		}
		gen_perm_next(gen_perm_data_p, tree_p, num_group);
	}
}

static void _generate_oper_perm_deal(num_group_s num_group,
				     deal_tree_ft* deal_f,
				     value_space_t* space_p, tree34_t* tree_p,
				     gen_oper_data_t* gen_oper_data_p) {
	while (1) {
		gen_perm_data_t gen_perm_data;
		gen_perm_init(&gen_perm_data, tree_p, num_group);
		_generate_perm_deal(num_group, deal_f, space_p, tree_p,
				    &gen_perm_data);
		if (!gen_oper_has_next(gen_oper_data_p)) {
			break;
		}
		gen_oper_next(gen_oper_data_p, tree_p);
	}
}

static void _generate_tree_oper_perm_deal(num_group_s num_group,
					  deal_tree_ft* deal_f,
					  value_space_t* space_p,
					  tree34_t* tree_p) {
	while (1) {
		gen_oper_data_t gen_oper_data;
		gen_oper_init(&gen_oper_data, tree_p);
		_generate_oper_perm_deal(num_group, deal_f, space_p, tree_p,
					 &gen_oper_data);
		if (!gen_tree_has_next(tree_p)) {
			break;
		}
		gen_tree_next(tree_p);
	}
}

void generate_all_solutions(num_group_s num_group, deal_tree_ft* deal_f) {
	tree34_t tree;
	value_space_t value_space;
	value_space.value_n_p = value_space.value_a;
	tree_init_ex_oper_num(&tree);
	_generate_tree_oper_perm_deal(num_group, deal_f, &value_space, &tree);
}
